#include <iostream>
#include <cassert>
#include <time.h>
#include <unistd.h>
#include <vector>
#include <string>
#include <sys/wait.h>
#include <sys/types.h>
using namespace std;
#define ProcessNum 4//创建子进程个数
typedef void(*func)();
#define makeseed() srand((unsigned long)time(nullptr)^getpid()^12494%1234)//使随机数更加的随机
//创建多个任务,模拟一下
void FuncTask1()
{
    cout<<getpid()<<"子进程完成任务1"<<endl;
}

void FuncTask2()
{
    cout<<getpid()<<"子进程完成任务2"<<endl;
}

void FuncTask3()
{
    cout<<getpid()<<"子进程完成任务3"<<endl;
}

//安排任务
void LoadTask(vector<func>& task)
{
    task.push_back(FuncTask1);
    task.push_back(FuncTask2);
    task.push_back(FuncTask3);
}

//下面就是进程间通信部分
class subEp
{
public:
    subEp(pid_t subid ,int writefd)
    :_subid(subid),_writefd(writefd)
    {
        char name[1024];
        snprintf(name,sizeof name,"process- %d [fd:%d ,id:%d]",_num++,_writefd,_subid);
        _name = name;
    }
public:
    static int _num;//子进程个数
    pid_t _subid;
    string _name;//每个子进程的名字
    int _writefd;//父进程给子进程发任务所需要的fd
};

int subEp::_num = 0;

int RecvTask(int fd)
{
    int code;
    int s = read(fd,&code,sizeof code);//接受父进程传过来的任务码
    if(s == 4) return code;
    else if(s <= 0) return -1;
    else return 0;
}

void CreateProcess(vector<subEp>& subs,vector<func>& task)
{
    vector<int> deletefd;//这里是为了防止创建子进程的时候发生写时拷贝时
    //导致后面的子进程也有连接到前面的子进程的写端
    for(int i = 0;i<ProcessNum;++i)
    {
        //开启读写端
        int fds[2];
        int n = pipe(fds);
        assert(n == 0);
        //创建子进程
        pid_t id = fork();
        assert(id >= 0);
        if(id == 0)
        {
            for(int i = 0;i<deletefd.size();++i)
            {
                //关闭后面子进程和前面子进程的联系
                close(deletefd[i]);
            }
            //子进程接受任务
            close(fds[1]);
            while(1)
            {
                //接受命令码，并完成任务
                int commandCode = RecvTask(fds[0]);
                if(commandCode >= 0 && commandCode<task.size())
                {
                    task[commandCode]();
                }
                else if(commandCode == -1) break;
            }
            exit(0);
        }
        //父进程
        close(fds[0]);
        subEp sub(id,fds[1]);
        subs.push_back(sub);
        deletefd.push_back(fds[1]);
    }
}

void sendtask(const subEp& process,int taskidx)
{
    cout<<"send to process ->"<<process._name<<endl;
    ssize_t s = write(process._writefd,&taskidx,sizeof taskidx);
    assert(s == sizeof(int));
    (void)s;//不使用了，强转防止报错
}


void ControlProcess(vector<func>& task,vector<subEp>& subs,int taskcnt)
{
    int tasknum = task.size();
    int subnum = subs.size();
    //判断是否是永久进行
    bool forever = (taskcnt == 0? true:false);
    while(1)
    {
        //生成任务idx
        int taskidx = rand()%tasknum;
        //生成子进程idx
        int processidx = rand()%subnum;
        //传送任务
        sendtask(subs[processidx],taskidx);
        sleep(1);//让子进程完成任务
        if(!forever)
        {
            --taskcnt;
            if(taskcnt == 0)
            {
                break;
            }
        }
    }
    for(int i = 0; i < subnum; i++) close(subs[i]._writefd);//关闭写端
}

void WaitProcess(vector<subEp>& subs)
{
    for(int i = 0;i<subs.size();++i)
    {
        waitpid(subs[i]._subid,nullptr,0);
        cout<<"wait success"<<subs[i]._subid<<endl;
    }
}

int main()
{
    //创建随机数
    makeseed();
    //生成任务表
    vector<func> task;
    //安排子进程需要完成的任务
    LoadTask(task);
    //创建子进程，并进行管理
    vector<subEp> subs;
    CreateProcess(subs,task);
    //父进程控制子进程，向子进程发送命令码
    int taskcnt = 3;//发送任务的次数
    ControlProcess(task,subs,taskcnt);

    //回收子进程
    WaitProcess(subs);
    return 0;
}